package com.chuangke.admin.service.impl;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chuangke.admin.constant.SysConstant;
import com.chuangke.admin.dao.mapper.SysUserMapper;
import com.chuangke.admin.data.builder.DeptDataBuilder;
import com.chuangke.admin.data.builder.DictDataBuilder;
import com.chuangke.admin.dto.DataPermissionRequest;
import com.chuangke.admin.dto.RegisterBean;
import com.chuangke.admin.entity.SimpleSysUser;
import com.chuangke.admin.entity.SysDataPermission;
import com.chuangke.admin.entity.SysDept;
import com.chuangke.admin.entity.SysDict;
import com.chuangke.admin.entity.SysMenu;
import com.chuangke.admin.entity.SysRole;
import com.chuangke.admin.entity.SysUser;
import com.chuangke.admin.entity.SysUserAuditDept;
import com.chuangke.admin.entity.SysUserRole;
import com.chuangke.admin.service.SysDataPermissionService;
import com.chuangke.admin.service.SysDeptService;
import com.chuangke.admin.service.SysMenuService;
import com.chuangke.admin.service.SysRoleService;
import com.chuangke.admin.service.SysUserAuditDeptService;
import com.chuangke.admin.service.SysUserDataDeptService;
import com.chuangke.admin.service.SysUserRoleService;
import com.chuangke.admin.service.SysUserService;
import com.chuangke.admin.util.UserUtil;
import com.chuangke.common.constant.CacheKeyConstants;
import com.chuangke.common.constant.FileConstants;
import com.chuangke.common.constant.SysDictTypeConstants;
import com.chuangke.common.data.builder.DataBuildConfig;
import com.chuangke.common.data.builder.DataBuilder;
import com.chuangke.common.db.page.CkPageQuery;
import com.chuangke.common.db.page.PageUtil;
import com.chuangke.common.event.file.FileDbankRegistEvent;
import com.chuangke.common.exception.ChuangkeException;
import com.chuangke.common.utils.BusinessUtil;
import com.chuangke.common.utils.PasswordUtils;
import com.chuangke.common.utils.SecurityUtils;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;

@Service
public class SysUserServiceImpl implements SysUserService {

	public static final String INHERIT_ROLE = "1";
	@Autowired
	private SysMenuService sysMenuService;
	@Autowired
	private SysDeptService sysDeptService;
	@Autowired
	private SysUserRoleService sysUserRoleService;
	@Autowired
	private SysRoleService sysRoleService;
	@Autowired
	private SysUserDataDeptService sysUserDataDeptService;
	@Autowired
	private SysUserAuditDeptService sysUserAuditDeptService;
	@Autowired
	private SysDataPermissionService sysDataPermissionService;

	@Autowired
	private SysUserMapper sysUserMapper;

	@Autowired
	private ApplicationEventPublisher eventPublisher;

	@Override
	public void save(List<SysUser> records) {
		throw new ChuangkeException("暂不支持的方法");
	}

	@Override
	public void deleteByIds(List<String> ids) {
		throw new ChuangkeException("暂不支持的方法");
	}

	@Override
	public List<SysUser> findList() {
		Map<String, SysUser> map = ((SysUserService) AopContext.currentProxy()).findMap();
		return new ArrayList<>(map.values());
	}

	@Override
	public IPage<SysUser> page(CkPageQuery page) {
		List<SysUser> allList = ((SysUserService) AopContext.currentProxy()).findList();

		allList.sort((user1, user2) -> {
			if (user1.getId().length() != user2.getId().length()) {
				return user1.getId().length() - user2.getId().length();
			}
			return user1.getId().compareTo(user2.getId());
		});

		String name = (String) page.get("name");
		String email = (String) page.get("email");
		String status = (String) page.get("status");
		String deptIds = (String) page.get("deptId");
		String strb = (String) page.get("strb");
		if (deptIds == null) {
			deptIds = "";
		}
		String deptIdStr = deptIds;
		String[] deptArr = deptIds.split(",");

		List<SysUser> list = allList.stream().filter(user -> ((StrUtil.isBlank(name) || (StrUtil.isNotBlank(name)
				&& (user.getName().matches(".*" + name + ".*") || user.getNickName().matches(".*" + name + ".*")))
				&& (StrUtil.isBlank(email)
						|| (StrUtil.isNotBlank(email) && user.getEmail().matches(".*" + email + ".*"))))
				&& (StrUtil.isBlank(status)
						|| (StrUtil.isNotBlank(status) && Objects.equals(user.getStatus().toString(), status)))
				&& (StrUtil.isBlank(strb)
						|| (StrUtil.isNotBlank(strb) && Objects.equals(user.getStrb().toString(), strb)))
				&& (StrUtil.isBlank(deptIdStr)
						|| (StrUtil.isNotBlank(deptIdStr) && Arrays.asList(deptArr).contains(user.getDeptId())))))
				.collect(Collectors.toList());

		list = list.stream().sorted(Comparator.comparingInt(SysUser::getSort)).collect(Collectors.toList());

		IPage<SysUser> result = PageUtil.findPage(page, list);

//        result.setRecords(result.getRecords().stream()
//                .sorted(Comparator.comparingInt(SysUser::getSort))
//                .collect(Collectors.toList())) ;

		findUserRoles(result.getRecords());// 加载用户角色信息
		findUserDept(result.getRecords());// 加载机构
		return result;
	}

	@Transactional(rollbackFor = Exception.class)
	@CacheEvict(cacheNames = CacheKeyConstants.SYS_USER, key = "'" + CacheKeyConstants.SYS_USER + "'")
	@Override
	public void save(SysUser record) {
		if (BusinessUtil.isInsert(record.getId())) {
//            String userId = IdManager.nextId();
			String userId = record.getName();
			record.setId(userId);
			for (SysUserRole userRole : record.getUserRoles()) {
				userRole.setUserId(userId);
			}
			sysUserMapper.insert(record);

			// 咱不支出网盘
			eventPublisher.publishEvent(new FileDbankRegistEvent(this, userId, "p", record.getNickName() + "的网盘",
					new BigInteger(FileConstants.DEFAULT_DBANK_SIZE)));
		} else {
			sysUserMapper.update(record, new UpdateWrapper<SysUser>().lambda().eq(SysUser::getId, record.getId()));
		}
		updateUserRole(record);
	}

	@Transactional(rollbackFor = Exception.class)
	@CacheEvict(cacheNames = CacheKeyConstants.SYS_USER, key = "'" + CacheKeyConstants.SYS_USER + "'")
	@Override
	public void updateBaseInfo(SysUser sysUser) {
		sysUserMapper.update(sysUser, new UpdateWrapper<SysUser>().lambda().eq(SysUser::getId, sysUser.getId()));
	}

	@Transactional(rollbackFor = Exception.class)
	@CacheEvict(cacheNames = CacheKeyConstants.SYS_USER, key = "'" + CacheKeyConstants.SYS_USER + "'")
	@Override
	public void updateUserOtherName(SysUser sysUser) {
		sysUserMapper.update(sysUser,new UpdateWrapper<SysUser>().lambda().set(SysUser::getAdName, sysUser.getAdName())
				.set(SysUser::getUidName, sysUser.getUidName()).eq(SysUser::getId, sysUser.getId()));
	}

	private void updateUserRole(SysUser record) {
		for (SysUserRole sysUserRole : record.getUserRoles()) {
			sysUserRole.setUserId(record.getId());
		}
		sysUserRoleService.deleteByUserId(record.getId());
		sysUserRoleService.insert(record.getUserRoles());

		List<String> userRoleList = record.getUserRoles().stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
		List<SysUserAuditDept> roleDeptList = sysUserAuditDeptService.findByUserRole(record.getId());
		List<String> notExistRoleList = roleDeptList.stream().map(SysUserAuditDept::getRoleId)
				.filter(roleId -> !userRoleList.contains(roleId)).collect(Collectors.toList());
		sysUserAuditDeptService.remove(record.getId(), notExistRoleList);

		DataPermissionRequest dpr1 = new DataPermissionRequest();
		dpr1.setType("user_duty");
		dpr1.setMaster1Id(record.getId());
		List<SysDataPermission> dprList = sysDataPermissionService.find(dpr1);
		List<String> notExistRoleList1 = dprList.stream().map(SysDataPermission::getMaster2Id)
				.filter(master2Id -> !userRoleList.contains(master2Id)).collect(Collectors.toList());
		notExistRoleList1.forEach(roleId -> {
			DataPermissionRequest dpr = new DataPermissionRequest();
			dpr.setType("user_duty");
			dpr.setMaster1Id(record.getId());
			dpr.setMaster2Id(roleId);
			sysDataPermissionService.delete(dpr);
		});
	}

	@CacheEvict(cacheNames = CacheKeyConstants.SYS_USER, key = "'" + CacheKeyConstants.SYS_USER + "'")
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void delete(SysUser record) {
		sysUserDataDeptService.delete(record.getId());
		sysUserRoleService.deleteByUserId(record.getId());
		sysUserAuditDeptService.deleteByUserId(record.getId());
		sysUserMapper.deleteById(record.getId());
	}

	@CacheEvict(cacheNames = CacheKeyConstants.SYS_USER, key = "'" + CacheKeyConstants.SYS_USER + "'")
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void delete(List<SysUser> records) {
		for (SysUser record : records) {
			delete(record);
		}
	}

	@Override
	@Cacheable(cacheNames = CacheKeyConstants.SYS_USER, key = "'" + CacheKeyConstants.SYS_USER + "'")
	public Map<String, SysUser> findMap() {
		List<SysUser> list = sysUserMapper.selectList(new QueryWrapper<>());
		bindName(list);
		return list.stream().collect(Collectors.toMap(SysUser::getId, a -> a));
	}

	@Override
	public SysUser findById(String id) {
		Map<String, SysUser> map = ((SysUserService) AopContext.currentProxy()).findMap();
		return map.get(id);
	}

	@Override
	public SysUser findByName(String name) {
		Map<String, SysDept> deptMap = sysDeptService.findMap();
		Map<String, SysUser> map = ((SysUserService) AopContext.currentProxy()).findMap();
		for (SysUser user : map.values()) {
			if (user.getName().equals(name)) {
				if (user.getDeptId() != null && !"".equals(user.getDeptId())) {
					SysDept sysDept = deptMap.get(user.getDeptId());
					user.setDeptName(sysDept == null ? "" : sysDept.getName());
				}
				return user;
			}
		}
		return null;
	}

	@Override
	public SysUser findByNickName(String nickName) {
//        Map<String, SysDept> deptMap = sysDeptService.findMap();
		Map<String, SysUser> map = ((SysUserService) AopContext.currentProxy()).findMap();
		for (SysUser user : map.values()) {
			if (user.getNickName().equals(nickName)) {
//                if (user.getDeptId() != null && !"".equals(user.getDeptId())) {
//                    SysDept sysDept = deptMap.get(user.getDeptId());
//                    user.setDeptName(sysDept == null ? "" : sysDept.getName());
//                }
				return user;
			}
		}
		return null;
	}

	@Override
	public SysUser findByName(String adName, String uidName) {
		if (StrUtil.isEmpty(adName) && StrUtil.isEmpty(uidName)) {
			throw new ChuangkeException("账号为空");
		}
		//防止空判断
		adName = StrUtil.isBlank(adName) ? UUID.fastUUID().toString() : adName ;
		uidName = StrUtil.isBlank(uidName) ? UUID.fastUUID().toString() : uidName ;
		String noSuffixAdName = adName.indexOf('.') > 0 ? adName.substring(0, adName.indexOf('.')) : adName;
		
		List<SysUser> userList = ((SysUserService) AopContext.currentProxy()).findList();
		for (SysUser user : userList) {
			if (adName.equals(user.getAdName()) || uidName.equals(user.getUidName()) || adName.equals(user.getName())
					|| uidName.equals(user.getName()) || noSuffixAdName.equals(user.getName())) {
				return findByName(user.getName());
			}
		}
		return null;
	}

	@Override
	public SysUser findByPhone(String phoneNumber) {
		Map<String, SysDept> deptMap = sysDeptService.findMap();
		Map<String, SysUser> map = ((SysUserService) AopContext.currentProxy()).findMap();
		for (SysUser user : map.values()) {
			if (user.getMobile().equals(phoneNumber)) {
				if (user.getDeptId() != null && !"".equals(user.getDeptId())) {
					SysDept sysDept = deptMap.get(user.getDeptId());
					user.setDeptName(sysDept == null ? "" : sysDept.getName());
				}
				return user;
			}
		}
		return null;
	}

	@Override
	public SimpleSysUser findSimpleById(String id) {
		SysUser sysUser = findById(id);
		return UserUtil.getSimpleSysUser(sysUser);
	}

	@Override
	public SimpleSysUser findSimpleByName(String username) {
		SysUser sysUser = findByName(username);
		return UserUtil.getSimpleSysUser(sysUser);
	}

	private void findUserDept(List<SysUser> userList) {
		if (CollectionUtils.isEmpty(userList)) {
			return;
		}
		Map<String, SysDept> map = sysDeptService.findMap();
		for (SysUser sysUser : userList) {
			SysDept dept = map.get(sysUser.getDeptId());
			sysUser.setDeptName(dept == null ? "" : dept.getName());
		}
	}

	/**
	 * 加载用户角色
	 *
	 */
	private void findUserRoles(List<SysUser> userList) {
		if (CollectionUtils.isEmpty(userList)) {
			return;
		}
		Map<String, List<SysUserRole>> map = sysUserRoleService.findAll();
		for (SysUser sysUser : userList) {
			List<SysUserRole> userRoles = map.get(sysUser.getId());
			sysUser.setUserRoles(userRoles);
			sysUser.setRoleNames(getRoleNames(userRoles));
		}
	}

	private String getRoleNames(List<SysUserRole> userRoles) {
		if (userRoles == null || userRoles.isEmpty()) {
			return "";
		}

		Map<String, SysRole> map = sysRoleService.findMap();
		StringBuilder sb = new StringBuilder();
		for (Iterator<SysUserRole> iter = userRoles.iterator(); iter.hasNext();) {
			SysUserRole userRole = iter.next();
			SysRole sysRole = map.get(userRole.getRoleId());
			if (sysRole == null) {
				continue;
			}
			sb.append(sysRole.getRemarks());
			if (iter.hasNext()) {
				sb.append(", ");
			}
		}
		return sb.toString();
	}

	@Override
	public Set<String> findPermissions(String userName) {
		Set<String> perms = new HashSet<>();
		List<SysMenu> sysMenus = sysMenuService.findByUser(userName);
		for (SysMenu sysMenu : sysMenus) {
			if (sysMenu.getPerms() != null && !"".equals(sysMenu.getPerms())) {
				perms.add(sysMenu.getPerms());
			}
		}
		perms.add(SysConstant.LOGIN_PERMS);
		return perms;
	}

	@Override
	public void passwd(SysUser sysUser) {
		sysUserMapper.update(null, new UpdateWrapper<SysUser>().lambda()
				.set(SysUser::getPassword, sysUser.getPassword()).eq(SysUser::getId, sysUser.getId()));
	}

	@Override
	@CacheEvict(cacheNames = CacheKeyConstants.SYS_USER, key = "'" + CacheKeyConstants.SYS_USER + "'")
	public int changeStatus(List<String> ids, String status) {
		return sysUserMapper.update(null,
				new UpdateWrapper<SysUser>().lambda().set(SysUser::getStatus, status).in(SysUser::getId, ids));
	}

	@Override
	public List<SysUser> findUsersByRoleId(String roleId) {
		List<SysUser> list = sysUserMapper.findUsersByRoleId(roleId);
		findUserRoles(list);// 加载用户角色信息
		findUserDept(list);// 加载机构
		bindName(list);
		return list;
	}

	@Override
	public List<SysUser> findUsersByDeptId(List<String> deptIdList) {
		Map<String, SysUser> map = ((SysUserService) AopContext.currentProxy()).findMap();
		List<SysUser> list = map.values().stream().filter(user -> deptIdList.contains(user.getDeptId()))
				.collect(Collectors.toList());
		findUserRoles(list);// 加载用户角色信息
		findUserDept(list);// 加载机构
		bindName(list);
		return list;
	}

	private void bindName(List<SysUser> list) {
		DataBuilder.of(list).appendBuilder(new DeptDataBuilder(), new DataBuildConfig("deptId", "deptName"))
				.appendBuilder(new DictDataBuilder(SysDict.TYPE_POST), new DataBuildConfig("postId", "postName"))
				.appendBuilder(new DictDataBuilder(SysDict.TYPE_JOBTYPE), new DataBuildConfig("jobType", "jobTypeName"))
				.appendBuilder(new DictDataBuilder(SysDictTypeConstants.QHSE_ACTION_TYPE),
						new DataBuildConfig("strb", "strbName"))
				.build();
	}

	@Override
	public List<SysUser> findUsersInheritRole(String roleId) {
		List<SysUser> list = findUsersByRoleId(roleId);
		return list.stream().filter(item -> INHERIT_ROLE.equals(item.getIsInheritRole())).collect(Collectors.toList());
	}

	@CacheEvict(cacheNames = CacheKeyConstants.SYS_USER, key = "'" + CacheKeyConstants.SYS_USER + "'")
	@Override
	public void changeInheritRole(String userId, String isInheritRole) {
		sysUserMapper.update(null, new UpdateWrapper<SysUser>().lambda().set(SysUser::getIsInheritRole, isInheritRole)
				.eq(SysUser::getId, userId));
	}

	@Override
	@CacheEvict(cacheNames = CacheKeyConstants.SYS_USER, key = "'" + CacheKeyConstants.SYS_USER + "'")
	public void resetPassword(String password, List<String> userIdList) {
		List<SysUser> userList = new ArrayList<>();
		for (String userId : userIdList) {
			SysUser user = new SysUser();
			user.setId(userId);
			user.setSalt(PasswordUtils.getSalt());
			user.setPassword(PasswordUtils.encode(true, password, user.getSalt()));
			userList.add(user);
		}
		for (SysUser user : userList) {
			sysUserMapper.update(null, new UpdateWrapper<SysUser>().lambda().set(SysUser::getSalt, user.getSalt())
					.set(SysUser::getPassword, user.getPassword()).eq(SysUser::getId, user.getId()));
		}
	}

	@Override
	public void register(RegisterBean registerBean) {
		String username = registerBean.getAccount();
		String password = registerBean.getPassword();
		// 用户信息
		SysUser user = findByName(username);
		if (user != null) {
			throw new ChuangkeException("账号已存在");
		}

		SysUser userInfo = new SysUser();
		userInfo.setDeptId(registerBean.getDeptId());
		userInfo.setName(username);
		userInfo.setNickName(registerBean.getName());
		userInfo.setMobile(registerBean.getPhone());
		userInfo.setPassword(PasswordUtils.encode(password, null));
		userInfo.setStatus((byte) 0);
		((SysUserService) AopContext.currentProxy()).save(userInfo);
	}

	@Override
	public void avatar(String base64) {
		String userId = SecurityUtils.getUserId();
		sysUserMapper.update(null,
				new UpdateWrapper<SysUser>().lambda().set(SysUser::getAvatar, base64).eq(SysUser::getId, userId));
	}

//	@Override
//	public List<SysUser> findUserByRoleName(String role) {
//		SysRole sysRole = sysRoleService.findByName(role) ;
//		
//		Map<String, List<SysUserRole>> map = ((SysUserRoleService) AopContext.currentProxy()).findAll();
//		List<SysUserRole> allList = new ArrayList<>() ;
//		map.values().forEach(list-> allList.addAll(list));
//		List<String> roleList = allList.stream().filter(userRole->sysRole.getId().equals(userRole.getRoleId())).map(SysUserRole::getUserId).collect(Collectors.toList()) ;
//		Map<String,SysUser> allUser = ((SysUserService) AopContext.currentProxy()).findAll() ;
//		
//		return allUser.values().stream().filter(user->roleList.contains(user.getId())).collect(Collectors.toList());
//	}

//	@Override
//	public FileInfo avatar(MultipartFile file) {
//		String userId = SecurityUtils.getUserId();
//		FileInfo fileInfo;
//		try {
//			fileInfo = fileService.uploadFile(file, "fastdfs", userId);
//		} catch (Exception e) {
//			throw new RuntimeException(e);
//		}
//
//		SysUser sysUser = new SysUser();
//		sysUser.setId(userId);
//		sysUser.setAvatar(fileInfo.getId());
//
//		sysUserMapper.updateAvatarByPrimaryKey(sysUser);
//		return fileInfo;
//	}

}
